package com.datang.litejvm.loader;


import com.datang.litejvm.attribute.*;
import com.datang.litejvm.clz.*;
import com.datang.litejvm.clz.Class;
import com.datang.litejvm.constant.*;

import java.util.ArrayList;
import java.util.List;

/**
 * @author: 顶风少年
 * @Description: 解析Class形成ClassFile
 * @date: 13:55 2022/6/10
 **/
public class ClassParser {
    public Class parse(byte[] codes) {
        ByteCodeIterator byteCodeIterator = new ByteCodeIterator(codes);
        Class aClass = new Class();
        //魔数
        aClass.setMagic(this.parseMagic(byteCodeIterator));
        //小版本
        aClass.setMinorVersion(this.parseMinorVersion(byteCodeIterator));
        //大版本
        aClass.setMajorVersion(this.parseMajorVersion(byteCodeIterator));
        //常量池
        com.datang.litejvm.constant.ConstantPool constantPool = this.parseConstantPool(byteCodeIterator);
        aClass.setConstPool(constantPool);
        //访问标记
        aClass.setAccessFlag(this.parseAccessFlag(byteCodeIterator));
        //类
        aClass.setThisClassIndex(this.parseClassIndex(byteCodeIterator, constantPool));
        //父类
        aClass.setSuperClassIndex(this.parseSuperClassIndex(byteCodeIterator, constantPool));
        //接口
        aClass.setInterfaceIndexList(this.parseInterfaceIndex(byteCodeIterator, constantPool));
        //字段
        aClass.setFieldList(this.parseField(byteCodeIterator, constantPool));
        //方法
        aClass.setMethodList(this.parseMethod(byteCodeIterator, constantPool));
        return aClass;
    }


    /**
     * @author: 顶风少年
     * @Description: 读取魔数
     * @date: 11:32 2022/6/10
     **/
    private String parseMagic(ByteCodeIterator iter) {
        return iter.nextU4ToHexString();
    }

    /**
     * @author: 顶风少年
     * @Description: 读取小版本号
     * @date: 11:32 2022/6/10
     **/
    private int parseMinorVersion(ByteCodeIterator iter) {
        return iter.nextU2ToInt();
    }

    /**
     * @author: 顶风少年
     * @Description: 读取大版本号
     * @date: 11:32 2022/6/10
     **/
    private int parseMajorVersion(ByteCodeIterator iter) {
        return iter.nextU2ToInt();
    }

    /**
     * @author: 顶风少年
     * @Description: 读取常量池
     * @date: 11:25 2022/6/10
     **/
    private com.datang.litejvm.constant.ConstantPool parseConstantPool(ByteCodeIterator iter) {
        com.datang.litejvm.constant.ConstantPool constantPool = new com.datang.litejvm.constant.ConstantPool();
        //占位因为集合是从0开始,先把0占用了
        constantPool.addConstantInfo(new ConstantNullConstantInfo(constantPool));

        //常量池中的常量数量
        int pollSize = iter.nextU2ToInt() - 1;

        for (int i = 1; i <= pollSize; i++) {
            //获取常量项类型
            int tag = iter.nextU1toInt();

            if (tag == ConstantInfo.CONSTANT_METHOD_REF_INFO) {
                ConstantMethodRefInfo constantMethodRefInfo = new ConstantMethodRefInfo(constantPool);
                //连续两个都是2字节的引用
                int classInfoIndex = iter.nextU2ToInt();
                constantMethodRefInfo.setClassIndex(classInfoIndex);
                int nameAndTypeIndex = iter.nextU2ToInt();
                constantMethodRefInfo.setNameAndTypeIndex(nameAndTypeIndex);
                constantPool.addConstantInfo(constantMethodRefInfo);
            }
            if (tag == ConstantInfo.CONSTANT_FIELD_REF_INFO) {
                ConstantFieldRefInfo constantFieldrefInfo = new ConstantFieldRefInfo(constantPool);
                //连续两个都是2字节的引用
                int classInfoIndex = iter.nextU2ToInt();
                constantFieldrefInfo.setClassIndex(classInfoIndex);
                int nameAndTypeIndex = iter.nextU2ToInt();
                constantFieldrefInfo.setNameAndTypeIndex(nameAndTypeIndex);
                constantPool.addConstantInfo(constantFieldrefInfo);
            }
            if (tag == ConstantInfo.CONSTANT_STRING_INFO) {
                ConstantStringInfo constantStringInfo = new ConstantStringInfo(constantPool);
                //一个字节是字符串的引用
                int index = iter.nextU2ToInt();
                constantStringInfo.setIndex(index);
                constantPool.addConstantInfo(constantStringInfo);
            }
            if (tag == ConstantInfo.CONSTANT_CLASS_INFO) {
                ConstantClassInfo constantClassInfo = new ConstantClassInfo(constantPool);
                //如果是ClassInfo常量池紧跟的就是类名所指向的字符串常量位置
                int utf8Index = iter.nextU2ToInt();
                constantClassInfo.setNameIndex(utf8Index);
                constantPool.addConstantInfo(constantClassInfo);
            }
            if (tag == ConstantInfo.CONSTANT_UTF8_INFO) {
                ConstantUTF8Info constantUtf8Info = new ConstantUTF8Info(constantPool);
                //UTF8的长度
                int length = iter.nextU2ToInt();
                constantUtf8Info.setLength(length);
                //长度后边是内容
                String value = iter.nextUxToString(length);
                constantUtf8Info.setBytes(value);
                constantPool.addConstantInfo(constantUtf8Info);
            }
            if (tag == ConstantInfo.CONSTANT_NAME_AND_TYPE_INFO) {
                ConstantNameAndTypeInfo constantNameAndTypeInfo = new ConstantNameAndTypeInfo(constantPool);
                int index1 = iter.nextU2ToInt();
                constantNameAndTypeInfo.setNameIndex(index1);
                int index2 = iter.nextU2ToInt();
                constantNameAndTypeInfo.setDescriptorIndex(index2);
                constantPool.addConstantInfo(constantNameAndTypeInfo);
            }
        }
        return constantPool;
    }

    /**
     * @author: 顶风少年
     * @Description: 读取类访问标记
     * @date: 17:19 2022/6/10
     **/
    private ClassAccessFlag parseAccessFlag(ByteCodeIterator iter) {
        int flag = iter.nextU2ToInt();
        ClassAccessFlag classAccessFlag = new ClassAccessFlag(flag);
        return classAccessFlag;
    }

    /**
     * @author: 顶风少年
     * @Description: 类
     * @date: 18:35 2022/6/10
     **/
    private int parseClassIndex(ByteCodeIterator iter, com.datang.litejvm.constant.ConstantPool constantPool) {
        //类名常量项
        int thisClassIndex = iter.nextU2ToInt();
        return thisClassIndex;
    }

    /**
     * @author: 顶风少年
     * @Description: 父类
     * @date: 18:35 2022/6/10
     **/
    private int parseSuperClassIndex(ByteCodeIterator iter, com.datang.litejvm.constant.ConstantPool constantPool) {
        //父类名常量项
        int superIndex = iter.nextU2ToInt();
        return superIndex;
    }


    /**
     * @author: 顶风少年
     * @Description: 接口
     * @date: 18:35 2022/6/10
     **/
    private ArrayList<Integer> parseInterfaceIndex(ByteCodeIterator iter, com.datang.litejvm.constant.ConstantPool constantPool) {
        //接口个数
        int interfaceCount = iter.nextU2ToInt();
        //遍历接口常量项,都是两个字节
        ArrayList<Integer> interfaceIndexList = new ArrayList<>();
        for (int i = 0; i < interfaceCount; i++) {
            interfaceIndexList.add(iter.nextU2ToInt());
        }
        return interfaceIndexList;
    }


    /**
     * @author: 顶风少年
     * @Description: 字段
     * @date: 11:24 2022/6/12
     **/
    private List<Field> parseField(ByteCodeIterator iter, com.datang.litejvm.constant.ConstantPool pool) {
        List<Field> fieldList = new ArrayList<>();
        int fieldCount = iter.nextU2ToInt();
        for (int i = 0; i < fieldCount; i++) {
            //访问权限
            int accessFlag = iter.nextU2ToInt();
            //属性名
            int nameIndex = iter.nextU2ToInt();
            //属性类型
            int descIndex = iter.nextU2ToInt();
            int attribCount = iter.nextU2ToInt();
            if (attribCount > 0) {//todo 没有属性,但是暂时待定
                throw new RuntimeException("Field Attribute has not been implemented");
            }
            FieldAccessFlag fieldAccessFlagInfo = new FieldAccessFlag(accessFlag);
            Field field = new Field(fieldAccessFlagInfo, nameIndex, descIndex, attribCount);
            fieldList.add(field);
        }
        return fieldList;
    }

    /**
     * @author: 顶风少年
     * @Description: 方法
     * @date: 18:33 2022/6/12
     **/
    private List<Method> parseMethod(ByteCodeIterator iter, com.datang.litejvm.constant.ConstantPool pool) {
        List<Method> methodList = new ArrayList<>();
        int methodCount = iter.nextU2ToInt();
        for (int i = 0; i < methodCount; i++) {
            //访问权限
            int accessFlag = iter.nextU2ToInt();
            MethodAccessFlag methodAccessFlag = new MethodAccessFlag(accessFlag);
            //方法名
            int nameIndex = iter.nextU2ToInt();
            //方法签名
            int descriptorIndex = iter.nextU2ToInt();
            //属性个数，此处为1 类型Code
            int attributeCount = iter.nextU2ToInt();

            //解析Code
            //code类型
            int attributeNameIndex = iter.nextU2ToInt();
            ConstantUTF8Info attributeNameInfo = (ConstantUTF8Info) pool.getConstantInfo(attributeNameIndex);
            String attributeNameValue = attributeNameInfo.getBytes();
            if (attributeNameValue.equals(AttributeInfo.CODE)) {
                //属性长度
                int attributeLength = iter.nextU4ToInt();
                CodeAttr codeAttr = new CodeAttr(attributeNameIndex, attributeNameValue, attributeLength);
                codeAttr.parse(iter, pool);
                Method method = new Method(methodAccessFlag, nameIndex, descriptorIndex, attributeCount, codeAttr,pool);
                methodList.add(method);
            }

        }
        return methodList;
    }
}
